package org.creavi.engine.model;

import java.util.ArrayList;

import com.jme.animation.SpatialTransformer;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jmex.model.animation.KeyframeController;

public class ModelInstance extends Controller {
	private static final long serialVersionUID = 1L;

	private ArrayList<KeyframeController> keyframeControllers;
	private Node modelNode;
	private ModelDefinition modelDefinition;
	private SpatialTransformer spatialTransformer;

	public ModelInstance(String instanceName, ModelDefinition modelDefinition) {
		keyframeControllers = new ArrayList<KeyframeController>();
		modelNode = new Node(instanceName);
	}

	public ArrayList<KeyframeController> getKeyframeControllers() {
		return keyframeControllers;
	}

	public Node getModelNode() {
		return modelNode;
	}

	public void update(float time) {
		for (KeyframeController kfc : keyframeControllers) {
			if (kfc.isActive()) {
				kfc.update(time);
			}
		}

		if (spatialTransformer != null) {
			if (spatialTransformer.isActive()) {
				spatialTransformer.update(time);
			}
		}
	}

	public ModelDefinition getModelDefinition() {
		return modelDefinition;
	}

	public void finalize() {
		modelDefinition.release();
	}

	public SpatialTransformer getSpatialTransformer() {
		return spatialTransformer;
	}

	public void setSpatialTransformer(SpatialTransformer spatialTransformer) {
		this.spatialTransformer = spatialTransformer;
	}

	public AdvancedKeyframeController getAdvancedKeyframeController() {
		if (keyframeControllers != null
				&& keyframeControllers.size() > 0
				&& keyframeControllers.get(0) instanceof AdvancedKeyframeController) {
			return (AdvancedKeyframeController) keyframeControllers.get(0);
		}

		return null;
	}

	public void playAndLoop(float time0, float time1) {
		final AdvancedKeyframeController akfc = getAdvancedKeyframeController();

		if (akfc != null) {
			final float t0 = time0, t1 = time1 > akfc.getMaxTime() ? akfc
					.getMaxTime() : time1;
			akfc.setKeyframeListener(new KeyframeListener() {

				public void afterApply(AdvancedKeyframeController kfc,
						float current) {
					for (KeyframeController kf : keyframeControllers) {
						kf.setNewAnimationTimes(t0, t1);
					}
					if (spatialTransformer != null
							&& spatialTransformer.keyframes.size() > 0) {
						spatialTransformer.setNewAnimationTimes(t0, t1);
					}
				}

				public void beforeApply(AdvancedKeyframeController kfc,
						float current, float update) {
					// no hagas nada :D
				}

			});
			akfc.setNotifyTime(t1);
			for (KeyframeController kf : keyframeControllers) {
				kf.setNewAnimationTimes(t0, t1);
				kf.setActive(true);
			}
			if (spatialTransformer != null
					&& spatialTransformer.keyframes.size() > 0) {
				spatialTransformer.setNewAnimationTimes(t0, t1);
				spatialTransformer.setActive(true);
			}
		}
	}

	public void playAndStop(float time0, float time1) {
		final AdvancedKeyframeController akfc = getAdvancedKeyframeController();

		if (akfc != null) {
			final float t0 = time0, t1 = time1 > akfc.getMaxTime() ? akfc
					.getMaxTime() : time1;
			akfc.setKeyframeListener(new KeyframeListener() {

				public void afterApply(AdvancedKeyframeController kfc,
						float current) {
					akfc.setKeyframeListener(null);

					for (KeyframeController kf : keyframeControllers) {
						kf.setActive(false);
					}
					if (spatialTransformer != null
							&& spatialTransformer.keyframes.size() > 0) {
						spatialTransformer.setActive(false);
					}
				}

				public void beforeApply(AdvancedKeyframeController kfc,
						float current, float update) {
					// no hagas nada :D
				}

			});
			akfc.setNotifyTime(t1);
			for (KeyframeController kf : keyframeControllers) {
				kf.setNewAnimationTimes(t0, t1);
				kf.setActive(true);
			}
			if (spatialTransformer != null
					&& spatialTransformer.keyframes.size() > 0) {
				spatialTransformer.setNewAnimationTimes(t0, t1);
				spatialTransformer.setActive(true);
			}
		}
	}

	public void playThenLoop(float time0, float time1, float loop0, float loop1) {
		final AdvancedKeyframeController akfc = getAdvancedKeyframeController();

		if (akfc != null) {
			final float l0 = loop0, l1 = loop1;
			final float t0 = time0, t1 = time1 > akfc.getMaxTime() ? akfc
					.getMaxTime() : time1;
			akfc.setKeyframeListener(new KeyframeListener() {

				public void afterApply(AdvancedKeyframeController kfc,
						float current) {
					akfc.setKeyframeListener(null);

					playAndLoop(l0, l1);
				}

				public void beforeApply(AdvancedKeyframeController kfc,
						float current, float update) {
					// no hagas nada :D
				}

			});
			akfc.setNotifyTime(t1);
			for (KeyframeController kf : keyframeControllers) {
				kf.setNewAnimationTimes(t0, t1);
				kf.setActive(true);
			}
			if (spatialTransformer != null
					&& spatialTransformer.keyframes.size() > 0) {
				spatialTransformer.setNewAnimationTimes(t0, t1);
				spatialTransformer.setActive(true);
			}
		}
	}

	public void playThenNotify(float time0, float time1, Notifier n,
			Object value) {
		final Notifier notifier = n;
		final Object valueEvent = value;
		final AdvancedKeyframeController akfc = getAdvancedKeyframeController();

		if (akfc != null) {
			final float t0 = time0, t1 = time1 > akfc.getMaxTime() ? akfc
					.getMaxTime() : time1;
			akfc.setKeyframeListener(new KeyframeListener() {

				public void afterApply(AdvancedKeyframeController kfc,
						float current) {
					akfc.setKeyframeListener(null);

					for (KeyframeController kf : keyframeControllers) {
						kf.setActive(false);
					}
					if (spatialTransformer != null
							&& spatialTransformer.keyframes.size() > 0) {
						spatialTransformer.setActive(false);
					}

					if (notifier != null) {
						notifier.notifyEvent(valueEvent);
					}
				}

				public void beforeApply(AdvancedKeyframeController kfc,
						float current, float update) {
					// no hagas nada :D
				}

			});
			akfc.setNotifyTime(t1);
			for (KeyframeController kf : keyframeControllers) {
				kf.setNewAnimationTimes(t0, t1);
				kf.setActive(true);
			}
			if (spatialTransformer != null
					&& spatialTransformer.keyframes.size() > 0) {
				spatialTransformer.setNewAnimationTimes(t0, t1);
				spatialTransformer.setActive(true);
			}
		}
	}
}
